package com.example.demo.controller;

import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.example.demo.bizmq.BiMessageProducer;
import com.example.demo.manager.RedisLimiterManager;
import com.example.demo.model.Chart;
import com.example.demo.model.Recommend;
import com.example.demo.payload.DataRequest;
import com.example.demo.payload.DataResponse;
import com.example.demo.service.ChartService;
import com.example.demo.service.RecommendService;
import com.example.demo.service.UserService;
import com.example.demo.utils.CommonMethod;
import com.example.demo.utils.SpiderUtils.Spider;
import com.example.demo.utils.SpiderUtils.WebContent;
import org.apache.commons.compress.utils.FileNameUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;


import static com.example.demo.service.impl.AiServiceImpl.*;
import static com.example.demo.service.impl.ExcelToCSVServiceImpl.convertExcelToCsv;
import static com.example.demo.utils.ResolveUtils.WordUtil.readWord;


@RestController
@Component
@RequestMapping("/api/ai")
public class AiController {
    @Resource
    private RedisLimiterManager redisLimiterManager;
    @Resource
    private UserService userService;
    @Resource
    private RecommendService recommendService;
    @Resource
    private ChartService chartService;
    @Resource
    private BiMessageProducer biMessageProducer;

    /**
     * @Auther: XuZH
     * @param file
     * @param necessary
     * @param name
     * @param chartType
     * @param userAccount
     * @return
     * @throws NoApiKeyException
     * @throws InputRequiredException
     */
    @PostMapping("/analyse")
    // 传入需求分析和文件，处理成csv，拼接信息，交给aigc处理
    // todo 可以增加一些完备性，如文件格式校验、文件路径校验、ai格式返回是否存在问题、详尽报错信息
    public DataResponse update(
            @RequestParam("file") MultipartFile file,
            @RequestParam("necessary") String necessary,
            @RequestParam("name") String name,
            @RequestParam("chartType") String chartType,
            @RequestParam("userAccount") String userAccount) throws NoApiKeyException, InputRequiredException {
        // 上传文件处理
        String excelFilePath = "src/main/java/com/example/demo/service/impl/testDir"; // Excel文件路径 后续可更改
        try {
            // 保存文件逻辑
            byte[] bytes = file.getBytes();
            excelFilePath = excelFilePath + "/" + file.getOriginalFilename();
            Path path = Paths.get(excelFilePath);
            Files.write(path, bytes);
            System.out.println(file.getOriginalFilename() + "保存成功");
        } catch (Exception e) {
            return CommonMethod.getReturnData(500, "文件保存失败：" + e.getMessage());
        }
        //进行限流
        int userId = userService.GetUserId(userAccount);
        redisLimiterManager.doRateLimit("genChartByAi_" + userId);
        // 拼接提示词
        if (necessary == null) necessary = "分析变化情况";
        String message = "分析需求：\n";
        message += necessary;
        message += "\n原始数据：\n";
        String csvString = convertExcelToCsv(excelFilePath, null);
        message += csvString;
        if (chartType == "") {
            message += "\n图表类型：\n";
            message += "折线图";
        } else if(chartType.equals("地图")){
            String result=genMapData(message);
            System.out.println(result);
            String code="",analyse="";
            String[] strings=result.split("【",2);
            code = strings[0];
            code=code.substring(code.indexOf('['));
            code=code.substring(0,code.lastIndexOf("]")+1);
            code = code.replaceAll("(\\w+):", "\"$1\":") // 为属性名添加双引号
                    .replaceAll("'(.*?)'", "\"$1\"") // 为字符串值添加双引号（假设没有其他单引号字符串）
                    .replaceAll(",\\s*]", "]"); // 去除数组最后一个元素后的逗号（如果存在）
            code="{\"tooltip\":{\"trigger\":\"item\"},\"toolbox\":{\"show\":true,\"orient\":\"vertical\",\"left\":\"right\",\"top\":\"center\",\"feature\":{\"dataView\":{\"readOnly\":false},\"restore\":{},\"saveAsImage\":{}}},\"visualMap\":{\"min\":0,\"max\":100,\"text\":[\"High\",\"Low\"],\"realtime\":false,\"calculable\":true,\"inRange\":{\"color\":[\"lightskyblue\",\"yellow\",\"orangered\"]}},\"series\":[{\"type\":\"map\",\"map\":\"china\",\"zoom\":1.5,\"center\":[\"104\",\"36\"],\"roam\":true,\"label\":{\"show\":true},\"itemStyle\":{\"areaColor\":\"#ccc\",\"borderColor\":\"#fff\"},\"visualMap\":{\"min\":0,\"max\":150,\"inRange\":{\"color\":[\"#FFD700\",\"#FF4500\"]},\"show\":false},\"data\":" +
                    code+"}]}";
            System.out.println(code);
            analyse = strings[1].replace("【", "");
            Map data = new HashMap();
            data.put("code", code);
            data.put("analyse", analyse);
            data.put("chartName", name);
            return CommonMethod.getReturnData(200, data, "分析ok!");
        }
        else {
            message += "\n图表类型：\n";
            message += chartType;
        }

//        提示词中间测试
//        System.out.println(message);
        String result = callWithMessage(message);
        // 这里做字符串之后的分割
        String code = "", analyse = "";
        System.out.println(result);
        // 遇到第一个】就分割成两个部分
        String[] strings = result.split("】", 2);
        code = strings[0].replace("【", "");
        analyse = strings[1].replace("【", "");
        code = code.replace("】", "");
        analyse = analyse.replace("】", "");
        Map data = new HashMap();
        data.put("code", code);
        data.put("analyse", analyse);
        data.put("chartName", name);
        return CommonMethod.getReturnData(200, data, "分析成功");
        /* 前端得到的结果 可参考：
{
    "code": 200,
    "data": {
        "code": "\n{\n  \"title\": \"网站用户增长情况\",\n  \"xAxis\": {\n    \"type\": \"category\",\n    \"data\": [\"1号\", \"2号\", \"3号\"]\n  },\n  \"yAxis\": {\n    \"type\": \"value\",\n    \"name\": \"用户数\"\n  },\n  \"series\": [\n    {\n      \"name\": \"用户增长\",\n      \"type\": \"line\",\n      \"data\": [10.0, 20.0, 30.0],\n      \"smooth\": true\n    }\n  ]\n}\n",
        "analyse": "\n\n数据分析结论：\n根据图表显示，网站用户在1号到3号期间呈现逐日增长的趋势。具体来说，1号用户数为10，2号增长到20，3号进一步增加到30，显示出网站的用户基础在稳步扩大。这可能是由于新用户注册增加、活跃度提升或者市场推广活动的效果。为了更深入地了解用户增长的驱动力，可能需要分析其他相关数据，如用户来源、留存率等。"
    },
    "msg": "分析成功"
}
         */
    }

    @PostMapping("/analyseWord")
    public DataResponse analyseWord(
            @RequestParam("file") MultipartFile file,
            @RequestParam("userAccount") String userAccount,
            @RequestParam("name") String chartName,
            @RequestParam("chartType") String chartType)throws NoApiKeyException, InputRequiredException{
        String excelFilePath = "src/main/java/com/example/demo/service/impl/testDir"; // 文件路径 后续可更改
        try {
            // 保存文件逻辑
            byte[] bytes = file.getBytes();
            excelFilePath = excelFilePath + "/" + file.getOriginalFilename();
            Path path = Paths.get(excelFilePath);
            Files.write(path, bytes);
            System.out.println(file.getOriginalFilename() + "保存成功");
        } catch (Exception e) {
            return CommonMethod.getReturnData(500, "文件保存失败：" + e.getMessage());
        }
        String message="";
        String extension= FileNameUtils.getExtension(file.getOriginalFilename());
        System.out.println(extension);
        message=readWord(extension,excelFilePath);
        if(chartType.equals("词云")){
            String result=genWordCloudData(message);
            System.out.println(result);
            String code="",analyse="";
            String[] strings=result.split("【",2);
            code = strings[0];
            code=code.substring(code.indexOf("["));
            code=code.substring(0,code.lastIndexOf("]")+1);
            System.out.println(code);
            code="{\"title\":{\"text\":" +
                    "\"" +chartName+"\""+
                    "},\"tooltip\":{\"show\":true},\"grid\":{\"left\":\"5%\",\"right\":\"5%\",\"bottom\":\"5%\",\"top\":\"5%\",\"containLabel\":true},\"series\":[{\"type\":\"wordCloud\",\"gridSize\":8,\"sizeRange\":[10,80],\"rotationRange\":[0,0],\"rotationStep\":45,\"shape\":\"circle\",\"drawOutOfBound\":false,\"layoutAnimation\":true,\"left\":\"center\",\"top\":\"center\",\"textStyle\":{\"fontFamily\":\"sans-serif\"},\"data\":" +
                    code +
                    ",\"emphasis\":{\"focus\":\"self\",\"textStyle\":{\"fontSize\":20}}}]}";
            analyse=strings[1];
            Map data = new HashMap();
            data.put("code", code);
            data.put("analyse", analyse);
            data.put("chartName", chartName);
            return CommonMethod.getReturnData(200,data,"okle");
        }
        else if(chartType.equals("关系图")){
            String result=genGraphData(message);
            System.out.println(result);
            String code="",analyse="";
            String[] strings=result.split("【",2);
            code = strings[0];
            code=code.substring(code.indexOf("["));
            code=code.substring(0,code.lastIndexOf("]")+1);
            code="{\"title\":{\"text\":" +
                    "\"" +chartName+"\""+
                    ",\"subtext\":\""+chartName+"\"" +
                    ",\"top\":\"bottom\",\"left\":\"right\"},\"tooltip\":{},\"legend\":[{\"data\":" +
                    "[]}]," +
                    "\"animationDuration\":1500,\"animationEasingUpdate\":\"quinticInOut\",\"series\":[{\"name\":\"Les Miserables\",\"type\":\"graph\",\"legendHoverLink\":\"false\",\"layout\":\"none\"," +
                    "\"data\":"+code +
                    ",\"roam\":\"true\",\"label\":{\"position\":\"right\",\"formatter\":\"{b}\"},\"lineStyle\":{\"color\":\"source\",\"curveness\":0.3},\"emphasis\":{\"focus\":\"adjacency\",\"lineStyle\":{\"width\":10}}}]}";
            analyse=strings[1];
            Map data = new HashMap();
            data.put("code", code);
            data.put("analyse", analyse);
            data.put("chartName", chartName);
            return CommonMethod.getReturnData(200,data,"okle");
        }
        return CommonMethod.getReturnData(200,"lala","okle");
    }

    @PostMapping("/analyse/jsmind")
    public DataResponse analyseJsmind(@RequestBody DataRequest dataRequest)throws NoApiKeyException, InputRequiredException{
        String url=dataRequest.getString("url");
        String message=Spider.fetchInfo(url);
        if(message.length()==0){
            return CommonMethod.getReturnData(208,message,"网页内容为空");
        }
        Recommend recommendUpdate=new Recommend();
        recommendUpdate.setId(recommendService.queryRecommendByUrl(url).getId());

        message="文本内容如下："+message;
        System.out.println(message);
        String result=genJsMind(message);
        System.out.println(result);
        int startIndex = result.indexOf('{') ; // 获取"json"后一个字符的位置
        int endIndex = result.lastIndexOf('}')+1;
        result=result.substring(startIndex,endIndex);
        System.out.println(result);
        //进行更新
        recommendUpdate.setURLData(result);
        recommendService.updateById(recommendUpdate);
        return CommonMethod.getReturnData(200,result,"ok");
    }


    @PostMapping("/analyse/jsonData")
    public DataResponse analyseJsonData(@RequestBody DataRequest dataRequest)throws NoApiKeyException, InputRequiredException{
        //String rawJson=dataRequest.getString("rawJson");
        String rawJson="[  \n" +
                "  {\"A\": \"省份\", \"B\": \"GDP\"},  \n" +
                "  {\"A\": \"山东\", \"B\": 10},  \n" +
                "  {\"A\": \"河南\", \"B\": 20},  \n" +
                "  {\"A\": \"陕西\", \"B\": 50},  \n" +
                "  {\"A\": \"山西\", \"B\": 15},  \n" +
                "  {\"A\": \"福建\", \"B\": 100},  \n" +
                "  {\"A\": \"河北\", \"B\": 60},  \n" +
                "  {\"A\": \"宁夏\", \"B\": 200},  \n" +
                "  {\"A\": \"甘肃\", \"B\": 10}  \n" +
                "]";
        String need=dataRequest.getString("need");
        String message="";
        message="原始JSON如下：\n"+rawJson+"\n";
        message=message+"需求如下：\n"+need+"\n";
        String result=genJsonData(message);
        System.out.println(result);
        int startIndex = result.indexOf('[') ; // 获取"json"后一个字符的位置
        int endIndex = result.lastIndexOf(']')+1;
        result=result.substring(startIndex,endIndex);
        System.out.println(result);
        return CommonMethod.getReturnData(200,result,"ok");
    }

    /**
     * @Auther: LYH
     * @param file
     * @param necessary
     * @param name
     * @param chartType
     * @param userAccount
     * @return
     * @throws NoApiKeyException
     * @throws InputRequiredException
     */
    @PostMapping("/analyse/mq")
    public DataResponse analyseMq(@RequestParam("file") MultipartFile file,
                                  @RequestParam("necessary") String necessary,
                                  @RequestParam("name") String name,
                                  @RequestParam("chartType") String chartType,
                                  @RequestParam("userAccount") String userAccount)throws NoApiKeyException, InputRequiredException {
        // 上传文件处理
        String excelFilePath = "src/main/java/com/example/demo/service/impl/testDir"; // Excel文件路径 后续可更改
        try {
            // 保存文件逻辑
            byte[] bytes = file.getBytes();
            excelFilePath = excelFilePath + "/" + file.getOriginalFilename();
            Path path = Paths.get(excelFilePath);
            Files.write(path, bytes);
            System.out.println(file.getOriginalFilename() + "保存成功");
        } catch (Exception e) {
            return CommonMethod.getReturnData(500, "文件保存失败：" + e.getMessage());
        }
        //进行限流
        int userId = userService.GetUserId(userAccount);
        System.out.println(userId);
        redisLimiterManager.doRateLimit("genChartByAi_" + userId);
        // 拼接提示词
        if (necessary == null) necessary = "分析变化情况";
        String csvString = convertExcelToCsv(excelFilePath, null);
        //直接新建一个表格
        Chart chart = new Chart();
        chart.setRawData(csvString);
        chart.setName(name);
        chart.setGoal(necessary);
        chart.setChartType(chartType);
        chart.setStatus("wait");
        chart.setUserId(userId);
        Date now=new Date();
        chart.setCreateTime(now);
        chart.setUpdateTime(now);
        chart.setIsDelete(0);

        boolean result=chartService.save(chart);
        int newChartId=chart.getId();;
//
//        //在消费者中进行AI处理，如生成结论，结构化数据
        biMessageProducer.sendMessage(String.valueOf(newChartId));
        return CommonMethod.getReturnData(200, 100, "分析成功");
    }


    @PostMapping("/analyseWord/mq")
    public DataResponse analyseWordMq(@RequestParam("file") MultipartFile file,
                                  @RequestParam("necessary") String necessary,
                                  @RequestParam("name") String name,
                                  @RequestParam("chartType") String chartType,
                                  @RequestParam("userAccount") String userAccount)throws NoApiKeyException, InputRequiredException {
        // 上传文件处理
        String excelFilePath = "src/main/java/com/example/demo/service/impl/testDir"; // 文件路径 后续可更改
        try {
            // 保存文件逻辑
            byte[] bytes = file.getBytes();
            excelFilePath = excelFilePath + "/" + file.getOriginalFilename();
            Path path = Paths.get(excelFilePath);
            Files.write(path, bytes);
            System.out.println(file.getOriginalFilename() + "保存成功");
        } catch (Exception e) {
            return CommonMethod.getReturnData(500, "文件保存失败：" + e.getMessage());
        }
        //进行限流
        int userId = userService.GetUserId(userAccount);
        System.out.println(userId);
        redisLimiterManager.doRateLimit("genChartByAi_" + userId);
        // 拼接提示词
        String message="";
        String extension= FileNameUtils.getExtension(file.getOriginalFilename());
        System.out.println(extension);
        message=readWord(extension,excelFilePath);
        //直接新建一个表格
        Chart chart = new Chart();
        chart.setRawData(message);
        chart.setName(name);
        chart.setGoal(necessary);
        chart.setChartType(chartType);
        chart.setStatus("wait");
        chart.setUserId(userId);
        Date now=new Date();
        chart.setCreateTime(now);
        chart.setUpdateTime(now);
        chart.setIsDelete(0);

        boolean result=chartService.save(chart);
        int newChartId=chart.getId();;
//
//        //在消费者中进行AI处理，如生成结论，结构化数据
        biMessageProducer.sendMessage(String.valueOf(newChartId));
        return CommonMethod.getReturnData(200, 100, "分析成功");
    }




    @PostMapping("/mock")
    // ai 反复调用 反应慢且消耗Token 故使用一个mock接口模拟 方便前端开发
    public DataResponse updateMock(
            @RequestParam("file") MultipartFile file,
            @RequestParam("necessary") String necessary) {
                /* 前端得到的结果 可参考：
{
    "code": 200,
    "data": {
        "code": "\n{\n  \"title\": \"网站用户增长情况\",\n  \"xAxis\": {\n    \"type\": \"category\",\n    \"data\": [\"1号\", \"2号\", \"3号\"]\n  },\n  \"yAxis\": {\n    \"type\": \"value\",\n    \"name\": \"用户数\"\n  },\n  \"series\": [\n    {\n      \"name\": \"用户增长\",\n      \"type\": \"line\",\n      \"data\": [10.0, 20.0, 30.0],\n      \"smooth\": true\n    }\n  ]\n}\n",
        "analyse": "\n\n数据分析结论：\n根据图表显示，网站用户在1号到3号期间呈现逐日增长的趋势。具体来说，1号用户数为10，2号增长到20，3号进一步增加到30，显示出网站的用户基础在稳步扩大。这可能是由于新用户注册增加、活跃度提升或者市场推广活动的效果。为了更深入地了解用户增长的驱动力，可能需要分析其他相关数据，如用户来源、留存率等。"
    },
    "msg": "分析成功"
}
         */
        Map data = new HashMap();
        data.put("code", "\\n{\\n  \\\"title\\\": \\\"网站用户增长情况\\\",\\n  \\\"xAxis\\\": {\\n    \\\"type\\\": \\\"category\\\",\\n    \\\"data\\\": [\\\"1号\\\", \\\"2号\\\", \\\"3号\\\"]\\n  },\\n  \\\"yAxis\\\": {\\n    \\\"type\\\": \\\"value\\\",\\n    \\\"name\\\": \\\"用户数\\\"\\n  },\\n  \\\"series\\\": [\\n    {\\n      \\\"name\\\": \\\"用户增长\\\",\\n      \\\"type\\\": \\\"line\\\",\\n      \\\"data\\\": [10.0, 20.0, 30.0],\\n      \\\"smooth\\\": true\\n    }\\n  ]\\n}\\n");
        data.put("analyse", "\\n\\n数据分析结论：\\n根据图表显示，网站用户在1号到3号期间呈现逐日增长的趋势。具体来说，1号用户数为10，2号增长到20，3号进一步增加到30，显示出网站的用户基础在稳步扩大。这可能是由于新用户注册增加、活跃度提升或者市场推广活动的效果。为了更深入地了解用户增长的驱动力，可能需要分析其他相关数据，如用户来源、留存率等。");
        return CommonMethod.getReturnData(200, data, "分析成功");
    }

    /**
     * @Auther: LWS
     * @param dataRequest
     * @return
     * @throws NoApiKeyException
     * @throws InputRequiredException
     */
    @PostMapping("/recommendByUserActions")
    public DataResponse recommendByUserActions(@RequestBody DataRequest dataRequest) throws NoApiKeyException, InputRequiredException {
        /*测试按照下面的格式
                {
          "data": {
            "userAccount":"admin2"
          }
        }
         */
        String userAccount=dataRequest.getString("userAccount");
        int userId= userService.GetUserId(userAccount);
        //根据userId拿到最近的4个分析图表
        List<Chart> userCharts=chartService.queryChartByUserId(userId);
        if(userCharts.size()==0){//此人没有任何分析记录，随机推荐
            List<Recommend> data=recommendService.randomRecommend();
            return CommonMethod.getReturnData(200,data,"ok了");
        }else{//此人有分析记录，ai分析推荐
            String userActions="";//用户的行为
            for (Chart chart : userCharts) {
                // 在这里你可以访问 chart 对象的属性，比如 chart.getId(), chart.getName() 等
                userActions+= chart.getGoal()+",";
                // ... 其他你需要的操作
            }
            //少用点token
            //String keywords=genKeywordByUserActions(userActions);
            //keywords=keywords.substring(4);
            String keywords="经济分析";
            List<Recommend> tempData=recommendService.RecommendByKeywords(keywords);
            //获取到data后进行处理获取，调用jsoup获取图片
            List<Map<String, Object>> totalData = new ArrayList<>();
            for(int i=0;i<tempData.size();i++){
                Recommend recommend=tempData.get(i);
                WebContent content = Spider.fetchTitleAndImages(recommend.getUrl());
                Map data = new HashMap();
                data.put("url", recommend.getUrl());
                data.put("title", recommend.getTitle());
                data.put("faviconUrl", content.getFaviconUrl());
                data.put("urlData",recommend.getURLData());
                totalData.add(data);
            }
            return CommonMethod.getReturnData(200,totalData,"推荐推荐！");
        }
    }

    //根据关键字进行爬虫，补充到数据库中
    @GetMapping("/getRecommend")
    public void getRecommend(String keyword) throws NoApiKeyException, InputRequiredException {
        JSONArray urls = null;
        if (keyword == null) return;
        try {
            // debug了好久 应该是汉字出现的错误，先转成UTF8再搞
            String encodedString = URLEncoder.encode(keyword, StandardCharsets.UTF_8.toString());
            // 目标URL
            String urlString = "http://120.46.145.218:5000/search?keyword=" + encodedString;
            // 用真的会等很久 开发使用mock出来的接口
//            String urlString = "http://120.46.145.218:5000/mock";
            // 创建URL对象
            URL getUrl = new URL(urlString);
            // 打开连接
            HttpURLConnection connection = (HttpURLConnection) getUrl.openConnection();
            // 设置请求方法为GET
            connection.setRequestMethod("GET");
            // 获取响应码，200表示成功
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                // 读取响应内容
                BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                StringBuilder content = new StringBuilder();
                String inputLine;
                while ((inputLine = in.readLine()) != null) {
                    content.append(inputLine);
                }
                in.close();
                // 解析JSON字符串为JSONArray
                urls = new JSONArray(content.toString());
                // @test
                System.out.println(urls);
            } else {
                System.out.println("GET request not worked, response code: " + responseCode);
            }
            connection.disconnect(); // 关闭连接
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 拿到了urls 开始处理
        if (urls == null) return;
        int step = 4;
        int times = urls.length() / step + 1;
        for (int j = 0; j < times; j++) {
            String message = "";
            for (int i = 0; i < step; i++) {
                int index = j * step + i;
                if (index >= urls.length() - 1) break;
                JSONArray url = new JSONArray(urls.get(index).toString());
                if (url.get(0).toString().startsWith("http") && !recommendService.isExists(url.get(0).toString()))
                    message += "{title:" + url.get(1) + ",url:" + url.get(0) + "}\n";
            }
            /*
你是一个归纳概括的专家，接下来我将按照固定格式给你一个关键词和若干标题和网址:
关键词：{关键词}
{title：{标题},url:{网址}}
...
{title：{标题},url:{网址}}
请根据以上的标题和关键词分析，提取关键词，关键词尽可能多，按照JSON数组格式输出（此外一定不要输出任何多余的开头、结尾、注释！！）
[
    {
        "title":{原来的标题},
        "keywords"::[{提取的关键词1},...,{提取的关键词2}],
        "url":{原来的网址}
    },
...
    {
        "title":{原来的标题},
        "keywords"::[{提取的关键词1},...,{提取的关键词2}],
        "url":{原来的网址}
    }
]
(每一条产生一行，若标题信息不足，该行可删去)
             */
            String role = "你是一个归纳概括的专家，接下来我将按照固定格式给你一个关键词和若干标题和网址:\n" +
                    "关键词：{关键词}\n" +
                    "{title：{标题},url:{网址}}\n" +
                    "...\n" +
                    "{title：{标题},url:{网址}}\n" +
                    "请根据以上的标题和关键词分析，提取关键词，关键词尽可能多，按照JSON数组格式输出（此外一定不要输出任何多余的开头、结尾、注释！！）\n" +
                    "[\n" +
                    "    {\n" +
                    "        \"title\":{原来的标题},\n" +
                    "        \"keywords\":[{提取的关键词1},...,{提取的关键词2}],\n" +
                    "        \"url\":{原来的网址}\n" +
                    "    }\n" +
                    "...\n" +
                    "    {\n" +
                    "        \"title\":{原来的标题},\n" +
                    "        \"keywords\":[{提取的关键词1},...,{提取的关键词2}],\n" +
                    "        \"url\":{原来的网址}\n" +
                    "    }\n" +
                    "]\n" +
                    "(每一条产生一行，若标题信息不足，该行可删去)";
            message = "关键词：" + keyword + "\n" + message;
            String answer = callWithMessageAndRole(message, role);
            answer = answer.replace("```json", "");
            answer = answer.replace("```", "");
            JSONArray jsonObjs;
            try {
                jsonObjs = new JSONArray(answer);
            } catch (Exception e) {
                continue;
            }
            for (int i = 0; i < jsonObjs.length(); i++) {
                JSONObject jsonObject = jsonObjs.getJSONObject(i);
                Recommend recommend = new Recommend();
                recommend.setTitle(jsonObject.getString("title"));
                recommend.setKeywords(jsonObject.getJSONArray("keywords").toString());
                recommend.setUrl(jsonObject.getString("url"));
                recommendService.add(recommend);
            }
        }
    }

    @PostMapping("/getRecommendByUrl")
    public DataResponse getRecommendByUrl(@RequestBody DataRequest dataRequest){
        String url=dataRequest.getString("url");
        Recommend recommend=recommendService.queryRecommendByUrl(url);
        return CommonMethod.getReturnData(200,recommend,"ok了");
    }

    @GetMapping("/test")
    public void test() {
        String str="[\n" +
                "  { name: '山东省', value: 10.0 },\n" +
                "  { name: '河南省', value: 20.0 },\n" +
                "  { name: '陕西省', value: 50.0 },\n" +
                "  { name: '山西省', value: 15.0 },\n" +
                "  { name: '福建省', value: 100.0 },\n" +
                "  { name: '河北省', value: 60.0 },\n" +
                "  { name: '宁夏回族自治区', value: 200.0 },\n" +
                "  { name: '甘肃省', value: 10.0 },\n" +
                "  { name: '新疆维吾尔自治区', value: 99.0 },\n" +
                "  { name: '西藏自治区', value: 50.0 },\n" +
                "  { name: '台湾省', value: 88.0 },\n" +
                "  { name: '湖北省', value: 100.0 },\n" +
                "  { name: '湖南省', value: 200.0 },\n" +
                "  { name: '江苏省', value: 45.0 },\n" +
                "  { name: '广东省', value: 70.0 },\n" +
                "  { name: '广西壮族自治区', value: 99.0 },\n" +
                "]\n";
        // 使用字符串替换修复JSON字符串
        String fixedStr = str.replaceAll("(\\w+):", "\"$1\":") // 为属性名添加双引号
                .replaceAll("'(.*?)'", "\"$1\"") // 为字符串值添加双引号（假设没有其他单引号字符串）
                .replaceAll(",\\s*]", "]"); // 去除数组最后一个元素后的逗号（如果存在）
        System.out.println(fixedStr);
    }
}
